Agent v3 chat - #832
Open
charles-ramos wants to merge 68 commits into
Open
Conversation
Fase A do porte production1 -> production2:
- src/dashboard/Data/Agent/ (Agent.react.js, Agent.scss, AgentConfigDialog.react.js)
e src/lib/AgentService.js
- Empty state com B4aEmptyState + botao Configure; dialog com B4aFormModal (padrao
visual do production2)
- Form "Configure" (localStorage, provider OpenAI) para o usuario informar a apiKey
pela UI, sem editar o config.json
- Rota /agent no Dashboard.js + secao Agent na sidebar (DashboardView)
- Parse-Dashboard/app.js: porta a rota POST /apps/:appId/agent + makeOpenAIRequest +
database tools + conversas; adiciona require('parse/node'); usa fetch global (Node 18,
sem node-fetch); express.json() escopado so na rota (production2 nao tem body-parser global)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
O package.json declarava core-js em 3.28.0 (dependencies) e 3.6.5 (devDependencies). Sem lockfile, o npm install deixava o 3.6.5 no topo, que nao tem modulos como es.error.cause.js/es.array.at.js/etc. O babel usa corejs '3.28' (useBuiltIns 'entry'), entao o `npm run dashboard` (webpack build.config.js) quebrava com ~40 erros "Can't resolve 'core-js/modules/...'". Alinhado ambos para 3.28.0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sem lockfile, o npm resolvia um tslib antigo (sem __spreadArray) no topo. O @amplitude/analytics-core chama tslib.__spreadArray em runtime -> TypeError -> tela branca no dashboard. tslib e transitivo (nao esta no package.json), entao forcei via "overrides" para 2.6.2 (tem __spreadArray, retrocompativel). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uction2 - Agent.scss convertido do tema claro (production1) para o dark do production2: fundo #0f1c32, superficies/bolhas/input escuros, texto claro, acento azul. Layout/estrutura mantidos. - Toolbar: section "Core" -> "Agent" (breadcrumb correto). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Porta da production1 os constraints que faltavam no production2: - matches (regex, String) -> query.matches(field, str, modifiers) - onOrBefore (Date) -> query.lessThanOrEqualTo - onOrAfter (Date) -> query.greaterThanOrEqualTo Definicoes em Constraints + FieldConstraints (String/Date) em src/lib/Filters.js, e os cases correspondentes em src/lib/queryFromFilters.js. O production2 ja tinha neq/keyNeq/stringContainsString. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…que) O BrowserCell do production2 importa B4aBrowserCell.scss, que NAO tinha as classes .selected/.leftBorder/.rightBorder/.topBorder/.bottomBorder. A logica de selecao (handleCellClick + selectedCells) ja funcionava, mas classes.push(styles.selected) empurrava undefined -> celula selecionava internamente mas nao pintava (nenhum erro no console). Copiadas as 5 regras do BrowserCell.scss normal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…curo - Cmd/Ctrl+C agora copia o INTERVALO de celulas selecionadas (tab/newline), nao so a celula focada. No production2 o range faz setCurrent(null) -> copyableValue undefined -> o case 67 existente nao copiava nada. Adicionado o copy multi-celula no topo do handleKey (guard >= 0 pra nao quebrar no estado inicial). - .selected: de #e3effd (claro) para rgba(22,105,252,.3) e bordas #1669fc — legivel no Data Browser escuro do production2 (antes o texto claro sumia no fundo azul-claro). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Portado da production1: no handleKey, case 32 (Space) faz toggle do selectRow da linha "current" (quando nao esta editando). production2 nao tinha esse case. Guards para this.props.selectRow/selection/data existirem. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lique pegar
O checkbox usava checked={selection['*'] || selection[obj.id]} sem coercao — quando
selection[id] era undefined, o input virava NAO-controlado, e a transicao
nao-controlado->controlado no clique fazia o React nao registrar a marcacao. Coercao
com !! (igual production1) mantem o input sempre controlado. O espaco ja funcionava
porque ia direto no selectRow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(upstream) Porta a feature drag-to-select da production1: mousedown num checkbox inicia o arrasto, cada checkbox que o mouse passa por cima marca/desmarca, mouseup encerra. - Browser.react: estado rowCheckboxDragging/draggedRowSelection, metodos onMouseDownRowCheckBox/onMouseUpRowCheckBox/onMouseOverRowCheckBox, listener global de mouseup, e passa os handlers pro DataBrowser (fluem via ...other ao BrowserTable). - BrowserTable: repassa onMouseDown/OverRowCheckBox aos 3 <BrowserRow>. - BrowserRow: checkbox com onMouseDown, checkCell com onMouseOver. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…orage Agora que o pre-production2 tem getEnvVars/updateEnvVars (feature do production2): - Configure -> Save: grava a apiKey na env var OPENAI_API_KEY do app (merge com as existentes via getEnvVars); dispara rebuild do app (comportamento da feature). - Agent carrega: le a apiKey via getEnvVars; partes nao-secretas (name/provider/model) ficam em localStorage. A chave nunca persiste no disco do browser. - Dialog: onSubmit retorna a promise -> modal mostra "Saving..." durante o rebuild e surface erros. Descricao do campo API Key atualizada. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- icon 'collaborate-solid' (nao existia no sprite -> item sem icone) trocado por 'b4a-agent' (icone dedicado que ja existe em src/icons). - Remove subsections: [] -> o Sidebar renderizava um submenu VAZIO (bloco grande em branco abaixo de "Agent"). Sem a chave subsections, o item fica compacto como o "Overview". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rtilhada
- AgentConfigDialog vira gerenciador de lista: 1 API Key compartilhada + N modelos
(Display name + model), com "+ Add model" e "Remove" por modelo.
- saveAgentConfig({apiKey, models}): grava a chave no env var OPENAI_API_KEY (uma so)
e a lista de modelos (nao-secreta) no localStorage; monta em memoria cada modelo
com a chave compartilhada.
- loadAgentConfig: le a lista do localStorage + a chave do env var.
- O seletor "Model" no toolbar do Agent ja itera models -> troca entre eles.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Troca os icones dos menus do toolbar do Agent (que vieram do upstream) pelos B4a: - Model: gear-solid -> b4a-app-settings-icon - Permissions: locked-solid -> b4a-lock-icon - Chat: collaborate-solid -> b4a-agent Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- B4aSidebarSection.getIconContent nao tinha case pro 'b4a-agent' -> no estado ATIVO caia no default (null) e o icone sumia. Add case que renderiza o sprite b4a-agent. - AgentConfigDialog: "+ Add model" (link no rodape) vira um botao "+" (b4a-add-outline-circle) no topo da secao Models, seguindo o padrao de "adicionar row". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Layout (offsets eram da production1): - left 300px -> 280px ($b4aSidebarWidth) no emptyStateOverlay e chatForm - top/padding-top 116px -> 127px (header 63 + toolbar 64 do production2) - sidebar colapsada: $sidebarCollapsedWidth -> 88px ($b4aSidebarCollapsedWidth) - agentContainer: removido o background navy de 100vh que vazava ACIMA do toolbar cinza (a region do header). O navy agora vem do chatWindow/emptyStateOverlay, abaixo do toolbar. Tooltips (title do BrowserMenu = tooltip nativo) mais descritivos: - Model -> "Select AI model" - Permissions -> "Permissions — what the agent can do in your database" - Chat -> "Chat options (clear conversation)" Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…at" vago Remove o menu "Chat" (que juntava Configure + Clear num icone so, pouco intuitivo) e coloca dois botoes diretos no toolbar: - "+" (b4a-add-outline-circle) -> abre o Configure (add/editar/remover modelos). tooltip "Add / configure models". - Clear (b4a-trash-icon) -> limpa a conversa. tooltip "Clear conversation". Estilo .toolbarAction (icone com padding + hover). clearChat ja guardava o browserMenuRef. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ixeira) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
lixeira parecia deletar dados, refresh parecia recarregar. O padrao de chat moderno para recomecar e o icone de compor/lapis = nova conversa. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lixeira parecia deletar dados, refresh parecia recarregar, lapis parecia editar/voltar. Texto "Clear" e inequivoco. Tooltip "Clear conversation". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
O upgradePrompt (newFeaturesInLatestVersion) aparecia na pagina /apps sugerindo atualizar o dashboard. Removido o bloco; upgradePrompt fica sempre null. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Rotulo no toolbar com o nome do modelo selecionado (title mostra o model id, ex. gpt-4o) — dá pra ver qual está ativo sem abrir o menu. - selectedAgentModel deixa de ser global e passa a ser por-app (selectedAgentModel_<slug>); setDefaultModel respeita a escolha salva do app ou cai no primeiro modelo. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tre apps) O componente Agent é reaproveitado ao navegar entre apps (só o contexto/slug muda, não há remount), então selectedModel/userAgentConfig/messages ficavam com os valores do app anterior. Agora detecta a troca de slug em componentDidUpdate e recarrega a partir do storage do app novo. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…alStorage Antes só a API key era env var; a lista de modelos ficava em localStorage (agentUserConfig_<slug>), o que fazia o display name vazar entre apps. Agora a config inteira (key em OPENAI_API_KEY + lista em AGENT_MODELS) é env var, então o backend é a única fonte por-app. Também guarda o render do modelo ativo no toolbar para só mostrar quando o modelo existe na lista do app atual. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…letar o agent - Remove o default "My model": o campo de display name começa vazio e, se ficar vazio, cai no id do modelo (ex. gpt-4). Assim nada aparece no toolbar antes de o usuário salvar um modelo de verdade. - Adiciona "Delete agent" (danger zone) no dialog: remove os env vars OPENAI_API_KEY e AGENT_MODELS, limpa a seleção por-app e volta ao empty state. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Em vez de POST /apps/:id/agent no servidor do dashboard (mandando a apiKey no corpo), o frontend agora chama POST /parse-app/:slug/agent na API back4app via ParseApp.sendAgentMessage(). A chave OpenAI é lida da env var do app no backend; o browser não envia mais segredo. O agent server-side é stateless, então o histórico recente é enviado a cada request. validateModelConfig não exige mais apiKey no cliente. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Em vez de campo livre pro id do modelo, um dropdown com modelos OpenAI comuns (gpt-4o, o3, gpt-5, ...) + opção "Custom…" que revela um campo de texto pra digitar qualquer id (ex. release nova). Evita typo e modelo inexistente sem travar quem quer um modelo fora da lista. O flag `custom` é só de UI (não é persistido); Save continua exigindo um model id. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
O agent deixa de rodar na API compartilhada e passa a rodar dentro do container do app do cliente, como uma Cloud Function (dashboardAgent). Assim escala com os recursos do próprio app e a chave nunca sai do container. - Novo cloud/dashboard-agent/index.js (dashboard-agent.cloud.js): loop OpenAI + tools via Parse SDK (useMasterKey local), lê OPENAI_API_KEY/AGENT_MODELS do env, exige master key. Importado como texto cru (webpack ?raw / asset/source). - agentCloudProvisioning.js: injeta/atualiza o arquivo gerenciado (marcador @back4app-dashboard-agent) e o require no main.js sem sobrescrever código do cliente; aborta com erro claro em colisão de nome; remove no delete. - ParseApp.getCloudCode/saveCloudCode; saveAgentConfig instala o cloud code ao salvar (colisão aborta antes de qualquer write), deleteAgentConfig remove. - Dialog mostra aviso explícito de que salvar instala Cloud Code e redeploya. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…le fallback Parse.Cloud.httpRequest was removed in Parse Server 6+. HTTP now uses global fetch (Node 18+) with a fallback to Node's built-in https module, so the Cloud Function also runs on Node 14 (fetch/AbortController are guarded and unused there). Clearer network/timeout error message. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…confusion The agent was inventing app IDs / server URLs and telling users it lacked the master key. Now the proxy passes the real app context (appId, appName, dashboardAPI serverURL) into the function, which injects it into the system prompt as authoritative values. Added instructions: DB access is already granted via tools (master key handled server-side) — never ask for it, never fabricate IDs/URLs/schema, and call getSchema/queryClass to answer instead of guessing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The homolog build still saw ts-invariant@0.4.4 (no setVerbosity) — the npm `overrides` field isn't reliably honored across environments/npm versions. Declare ts-invariant@^0.10.3 as a DIRECT dependency instead (portable: forces 0.10.3 to the top level on any npm; parse-server's old apollo chain gets a nested 0.4.4). Removed the conflicting override. Also hardcode the back4app2 client URL (dropped process.env to avoid the DefinePlugin conflict). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… button - renderContent() instead of render() so DashboardView keeps the sidebar/navbar (overriding render() bypassed the whole dashboard shell). - Use this.context.applicationId (ParseApp stores the appId there) — fixes "App context not available" and the currentAppId === appId match. - Empty state now offers a "Create agent" button when the app has no V3 agent: createAgent() calls sdk.createAgent(name,'V3') + setAgentCurrentApp(id, appId), then reloads the chat. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The back4app2 navbar provides the shared connect.sid session the agent SDK authenticates with — it must be mounted. It had been left commented out as a local workaround and got carried into the AgentV3 route commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- parseAgentContent(): strip the streamed ```agent-progress``` fences (and tool-call/tool-result/app-info fences + legacy "Using tool:" / "Done." lines), extract the events, and render only the clean text — fixes the broken task layout (raw JSON + empty Monaco blocks). While a message is in progress, show a compact task row (spinner + stage · tool · filePath) from the latest event. - Hyphen-safe code-fence language regex. - Delete agent: toolbar action → sdk.deleteAgent(agent.id) (with confirm) → resets to the empty/create state. (Create was already added.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The full-screen empty-state overlay (position:fixed) was covering the chat input whenever there were no messages — including right after creating an agent. Now the overlay shows ONLY when there is no agent (create/loading); once an agent exists, an inline centered hint renders inside the chat window and the input stays available below it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The parse-dashboard agent is the differentiated "v4" — a reduced, app-scoped agent segregated from the full v3/v5 flavors. findAgents/createAgent now use a single AGENT_FLAVOR constant so the backend flavor flips in one line. Kept at 'V3' for now (the chat works against real V3 agents); switch to 'V4' once the segregated v4 flavor lands in back4app2 + the Python agent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The back4app2 v4 flavor (AgentFlavor 'V4' + flavor column) and the Python agent v4 image are live, so the dashboard now creates/queries V4 agents. New agents created from the dashboard are persisted with flavor=V4; existing agents remain V3 (backfilled). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…agent Toolbar "API key" action opens a dialog to set the agent's own LLM keys (sdk.setAgentLLMCredentials). Blank fields keep the current key; keys are sent to the encrypted backend store and never shown back — only hasOpenaiApiKey/ hasAnthropicApiKey booleans are read to indicate a key is set. NOTE: needs @back4app2/sdk republished with setAgentLLMCredentials + the has* query fields, and the version bumped here, before it works at runtime. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The published SDK now exposes setAgentLLMCredentials + the agent flavor/has* fields, so the BYOK "API key" dialog works at runtime. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Invert the BYOK flow: "Create agent" now opens the credentials dialog FIRST, then creates the agent with the key already set. On a BYOK-only plan the key is what makes the agent usable, so creating first and asking after left the agent created-but-useless. The key stays optional (blank = platform default); the toolbar "API key" action still edits it later. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When the first message launches the container, the chat showed only bare typing dots — it looked like nothing happened until the agent suddenly became available. Use the ChatMessage status: INITIALIZING renders "Starting the agent…", INITIALIZED renders "Agent ready — thinking…". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The LLM key/provider is fixed for an agent's life (1 agent : 1 app, no reconfigure — switching OpenAI<->Anthropic means a new container = a new agent). Editing the key in place was misleading, so drop it: - "New agent": destructive — deletes the agent + conversation and provisions a fresh one, optionally with a new key. The ONLY way to switch the key/provider. Dialog warns the conversation is lost forever. - "Clear key": non-destructive — clears the BYOK key (back to the platform default) and keeps the conversation. Only shown when a key is set. No "clear chat": the conversation is server-side and the agent's context lives in its container, so a display-only clear would be a lie — "New agent" is the honest fresh start. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dialog now has a provider toggle (OpenAI | Anthropic) + a single key field, instead of two key fields. An agent uses ONE provider, so only the chosen provider's key is sent (the other is explicitly empty). Matches the 1-agent-1-provider model and avoids the "both keys" confusion. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Swap the OpenAI|Anthropic toggle for the dashboard's standard Dropdown + Option (same pattern as the old AgentConfigDialog) — reads better in the dialog and is theme-consistent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Delete and Clear-key now confirm with the dashboard's B4aModal (DANGER for delete, DEFAULT for clear) — the same danger dialog the Cloud Code section uses — instead of a native browser alert. Modal is held in state.modal and rendered inline; subtitleModal styling mirrors Cloud Code. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
For now V4 has no platform-key option: a key is required to create an agent. - Dialog: the key field is required (submit disabled until filled); copy no longer mentions a platform default. - Toolbar: drop "Clear key" (nothing to fall back to). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the text toolbar links with icon buttons (refresh = New agent, delete = Delete agent) with title tooltips, matching the Browser toolbar pattern. Cleaner toolbar; the tooltip carries the explanation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Container-startup failures arrive as a full Python traceback / log dump. Extract just the final "SomeError: message" line (e.g. "No LLM provider configured. Set ANTHROPIC_API_KEY or OPENAI_API_KEY.") for the chat error, falling back to the first line. Dashboard-only; no backend change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sending a message while the container is still starting returned "agent has not initialized". Disable the input (and show "Preparing your agent…") while the agent status is INITIALIZING/INITIALIZED/LAUNCHING, and poll getAgent until it reaches READY, then un-gate. Poll is cleared on unmount/app switch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The textarea was disabled during the in-flight send, dropping focus, so the user had to click back in before typing the next message. Keep the textarea enabled while sending (only the Send button disables) and refocus it after the send resolves. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cut the redundant "fixed / to switch create a new agent" (it's the new-agent dialog itself) and the "(required)" (the field already says Required). Down to one tight line per mode. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The borderless button read as flat/not-a-button. Reserve a transparent border in the base (no size jump) and color it when enabled (brighter on hover); disabled stays borderless. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dashboard agent is the V4 flavor, but the file/class/comments still said V3. Rename AgentV3.react.js -> AgentV4.react.js, the class AgentV3 -> AgentV4, and update the import + comments. No behavior change (branch name kept). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…vor) Follow-up to the file rename: class AgentV3 -> AgentV4, the Dashboard import path, and the V3-mentioning comments in AgentV4.react.js and back4app2Client.js. No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a Model dropdown (curated per provider + "Custom…" free-text) to the creation/new-agent dialog; provider switch resets the model. Model is required (Create disabled until key AND model are set) and passed to setAgentLLMCredentials(model). Provider lists: OpenAI = gpt-5.3-codex/5.5/ 5.6-terra; Anthropic = claude-sonnet-5/opus-4-8/sonnet-4-6. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The published SDK now carries the `model` arg on setAgentLLMCredentials and Agent.llmModel, so the create dialog's model choice reaches the backend. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
back4app2Client.js hardcoded the GraphQL endpoints to api.containers-homolog.back4app.com, so the Agent tab always talked to homolog regardless of environment. Locally that fails auth outright: the SDK authenticates with the shared `connect.sid` cookie, which is scoped to localhost and never reaches a .back4app.com host, surfacing in the UI as "Couldn't load the agent: unexpected error". b4aSettings.CONTAINERS_API_PATH already carries the right URL per environment (dev.json -> http://localhost:4040) and is what src/lib/back4app2.js uses. Use it here too, and derive the ws URL from the http one so the two can never drift apart. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B4aBadge positions itself with `float: right`, which works in the default section header (`display: block`) but silently does nothing once the section is active: `.active .section_header` switches to `display: flex`, and floats do not apply to flex items. The badge collapsed against the label with no gap the moment the section was clicked. `margin-left: auto` is the flex equivalent of the float. The badge's 5px top offset also goes, since `align-items: center` already handles the vertical alignment here. B4aBadge's class name is hashed by CSS Modules and cannot be referenced from this stylesheet, so the rule matches the last span only when it is not the only one — the label and the badge are both spans and the icon is an svg, so that is exactly "a badge follows the label". With no badge, or a collapsed sidebar where the label span is not rendered, nothing matches and the label is never pushed right. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…adge The product had three agents whose names barely differed: `agent` (v3), `agents` (v5) and this one. "Backend Agent" names it by the surface the user is actually on when they use it — the Backend dashboard — which is the axis they can tell apart without knowing about flavors or sandboxes. Also renames the user-facing strings that said "AI Agent": the empty states, the key dialog titles, and the Cloud Code collision errors. The sidebar's `section` prop is not cosmetic — B4aSidebar decides the active item with `name === section`, so the label and the Toolbar section have to move together or the item stops highlighting. The Toolbar subsection drops out entirely: "Backend Agent / AI Agent" was redundant, and single-page sections (Config, Cloud Code) already render without one. The icon becomes "AI" drawn as filled paths. Not `<text>`, which would depend on a font resolving inside the sprite, and not strokes: SvgPrepPlugin builds the sprite with `noFill: true` so icons inherit the color the Icon component sets as `fill`, and a stroked icon would keep its own color instead. `b4a-agent` stays — the AI Tools menu still uses it for the containers agent. So does the `/agent` route and the internal V4 flavor name. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
New Pull Request Checklist
Issue Description
Closes: FILL_THIS_OUT
Approach
TODOs before merging